﻿#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
#include"string.h"
using namespace std;
//// 传值返回需要拷⻉   //左值引用返回：什么也不打印   //右值引用返回：程序挂了
lin::string addStrings(lin::string num1, lin::string num2) {
	lin::string str;
	int end1 = num1.size() - 1, end2 = num2.size() - 1;
	// 进位
	int next = 0;
	while (end1 >= 0 || end2 >= 0)
	{
		int val1 = end1 >= 0 ? num1[end1--] - '0' : 0;
		int val2 = end2 >= 0 ? num2[end2--] - '0' : 0;
		int ret = val1 + val2 + next;
		next = ret / 10;
		ret = ret % 10;
		str += ('0' + ret);
	}
	if (next == 1)
		str += '1';
	reverse(str.begin(), str.end());
	//cout << &str << endl;
	return str;
}


void test1() //左值引用的主要使用场景
{
	//左值引⽤主要使⽤场景是：
	// 1、在函数中左值引⽤传参和左值引⽤传返回值时减少拷⻉，
	// 2、同时还可以修改实参和修改返回对象的价值。
	// 
	// 但是，左值引用无法解决的问题：
	// 左值引⽤已经解决⼤多数场景的拷⻉效率问题，但有些场景不能使⽤传
	//左值引⽤返回，如addStrings函数（两个数字字符串相加），C++98中的解决⽅案只能是被迫
	// 使⽤输出型参数解决（即将实参传给函数，用引用接收）。
	// 
	// 那么C++11以后这⾥可以使⽤右值引⽤做返回值解决吗？显然是不可能的，因为这⾥的本质是返回
	//对象是⼀个局部对象，函数结束这个对象就析构销毁了，右值引⽤返回也⽆法更改对象已经析构销毁
	//的事实。

	/*string ret = addStrings("11111", "22222");
	cout << ret << endl;*/
}

void test2() {
	lin::string s1("hello world");       //有参构造

	lin::string s2(lin::string("xiaomi"));  //有参构造
	                                       //这里本应该是有参构造+拷贝构造，编译器优化了
	
	lin::string s3(s1);  //拷贝构造

	lin::string s4(move(s2));  //移动构造 ,s2的数据和s4的交换了，s2数据变为NULL
}

void test3() //用lin::string 解决addstring的问题
{
	lin::string ret = addStrings("11111", "22222");
	cout << ret.c_str() << endl;
	cout << &ret << endl;
	//注意：vs2022的debug的优化十分厉害
	// 
	//一、传参过程中：
	// 不优化：
	// (1).string类没有移动构造： 两个：有参构造（临时对象）+ 拷贝构造（形参）
	// (2).stirng类有移动构造： 两个：有参构造（临时对象）+ 移动构造（形参）
	//  
	// 一代优化：
	// (1).string类没有移动构造： 两个：有参构造（形参）
	// (2).stirng类有移动构造： 两个：有参构造 （形参）

	//二、返回过程：
	// 不优化：
	// (1).string类没有移动构造：拷贝构造（构造出临时对象）+ 拷贝构造（ret拷贝临时对象）
	// (2).stirng类有移动构造：移动构造（构造出临时对象）+ 移动构造（ret与临时对象交换数据）
	//  
	// 一代优化：三合二（抹去临时对象）
	// (1).string类没有移动构造： 拷贝构造（ret拷贝被返回的那个对象）
	// (2).stirng类有移动构造： 移动构造（ret与被返回的那个对象交换数据）
	//
	// 二代优化：三合一
	//                       一个有参构造
	// string类有没有移动构造都无所谓，直接构造ret对象。
	// 对于函数内部对谁进行操作，可以认为是对ret的引用(str)进行操作
	//验证：addStirngs内的str的地址和ret的地址是一样的
	// 
	// 
	// 
	//vs2019的debug没有优化得那么厉害

	//交换数据具体交换的是：
	//
	// 如：vector类型：  交换_start、_finish、_end_of_storage 三个指针
	//     list类型：    交换_head指针
	//     set、map类型：交换_root指针
	// 
	//     因此交换数据比拷贝数据效率高得多

}

void test4() //移动赋值
{
	lin::string ret; //默认构造

	ret = addStrings("11111", "22222");
	cout << ret.c_str() << endl;
	 
	//对于这种情况，编译器无法再合三为一了，因为ret已经先构造了

	//无忧化：
	//
	//函数返回过程：
	//（1）无移动构造和移动赋值：拷贝构造(构造出临时变量)+拷贝赋值(临时变量赋值给ret)
	//（2）有移动构造和移动赋值：移动构造(构造出临时变量)+移动赋值(临时变量与ret交换数据)

	//一代优化：
	//（1）无移动构造和移动赋值：拷贝赋值(返回值str赋值给ret)
	//（2）有移动构造和移动赋值：移动赋值(返回值str与ret交换数据)

	//编译器只有优化到这种程度了,因此，对于这个场景，
	// 有右值引用才能解决拷贝赋值带来的消耗的问题
	//                                     

}


void test5() {  //需要有移动构造和移动赋值接口的容器

	//需要进行深拷贝的容器才需要移动构造和移动赋值
	//如：vector,string ,list ,map

	//像Date这样的类是不需要移动构造和移动赋值的
	//像Date这样的类，只需要复制
}
int main()
{ 
	test4();

	return 0;
}